// ## 2023/10/27 # 铃 # 据点周围防御

namespace 据点防御建设
{
    bool 调试模式 = true;
    class Main
    {

        Main()
        {
            pk::bind(202, pk::trigger202_t(onAIRunningOrder));

        }

        array<bool> arr_base_defence(据点_末, false);
        pk::list<pk::building @> list_enemy_building;
        pk::list<pk::person @> person_list;


        void onAIRunningOrder(pk::ai_context @context, pk::building @base, int cmd)
        {
            if (cmd == 据点AI_修建设施)
            {
                //加入概率
                if (int(pk::rand(200)) > int(sqrt(pk::get_gold(base))))
                    return;

                pk::list<pk::person @> person_list = pk::get_idle_person_list(base);
                if (person_list.count == 0)
                    return;

                   // 武将排序，
                   //由于建设的时候是有可能遇到敌人的,因此统率也不能忽视
                person_list.sort(function(a, b) {
                    int a_score = a.stat[武将能力_政治] * 2 + a.stat[武将能力_统率];
                    int b_score = b.stat[武将能力_政治] * 2 + b.stat[武将能力_统率];
                    // 考虑武将能力
                    return (a_score > b_score);
                });

                //最多只push10次
                for (int h = 0; h < pk::min(10,person_list.count); h++)
                {
                    PushCoveringUnit(base, person_list[h]);
                }

            }
        }

        bool PushCoveringUnit(pk::building @building, pk::person @person)
        {
            // 选择部队出征
            int max = 1;
            if (building.get_id() < 城市_末) max = 8;
            else max = 5;
            pk::point dst_pos1 = get_able_pos(building, 1, max);
            pk::point dst_pos2 = get_empty_pos(dst_pos1, 1, 1);

            if (dst_pos1 == -1)
                return false;

            if (dst_pos2 == -1)
                return false;

            //pk::trace(pk::decode(pk::get_name(building)) + "0目标" + dst_pos1.x + "  " + dst_pos1.y);


            // 出击
            int unit_id = push_unit(building, dst_pos1, dst_pos2, person, true);
            if (unit_id != -1)
                return true;

            return false;
        }

        int push_unit(pk::building @src_base, pk::point target_pos1, pk::point target_pos2, pk::person @person, bool do_cmd = true)
        {
            //pk::trace(pk::decode(pk::get_name(src_base)) + "1目标" +  123);

            int src_troops = pk::get_troops(src_base);
            if (src_troops <= 5000)
                return -1; // 兵力不足


            int reinforce_troops = pk::min(20000, pk::get_command(person), pk::max(1, pk::get_troops(src_base) - 5000));

                        // 选择最佳的武器
            int ground_weapon_id = 兵器_剑;
            int ground_weapon_score = 0;
            int water_weapon_id = 兵器_走舸;
            int unit_troops = reinforce_troops;

            //*******************  陆地兵器  ******************
            // 选择陆上武器
            ground_weapon_id = get_ground_weapon(src_base, person, 1).first;
            ground_weapon_score = get_ground_weapon(src_base, person, 1).second;

            //pk::trace(pk::decode(pk::get_name(person_list[0])) + get_weapon_name(ground_weapon_id) + "ground_weapon_id" + ground_weapon_id + "ground_weapon_score:" + ground_weapon_score + ",unit_troops :" + unit_troops);

            if (ground_weapon_score == 0 or ground_weapon_id == 0)
                return -1; // 兵器不足

            //pk::trace(pk::decode(pk::get_name(src_base)) + "4目标" +  123);

            if (ground_weapon_id <= 兵器_战马)
            {
                unit_troops = pk::min(unit_troops, pk::get_weapon_amount(src_base, ground_weapon_id));
                if (unit_troops < 3000) return -1;
            }

            //pk::trace(pk::decode(pk::get_name(src_base)) + "5目标" +  123);

            //********************  水上兵器  ***********************
            water_weapon_id = 兵器_走舸;

            int base_weight = 5;
            int unit_food = int(unit_troops);
            if (unit_food > int(pk::get_food(src_base) * 0.5))
                return -1;


            // 工事列表
            array<array<int>> facility_score = {
                {工事_阵, 0},
                {工事_箭塔, 0},
                {工事_投石台, 0},
                {工事_太鼓台, 0},
                {工事_军乐台, 0},
                {工事_石兵八阵, 0},
                {工事_土垒, 0} };

            for (int i = 0; i <= 6; ++i)
            {
                if (!pk::has_tech(src_base, 技巧_开发投石) and i == 工事_投石台)
                {
                    facility_score[i][1] == -1;
                    continue;
                }
                if (i == 工事_阵) facility_score[i][1] += 1 + pk::rand(3);
                if (i == 工事_箭塔) facility_score[i][1] += 3 + pk::rand(3);
                if (i == 工事_军乐台) facility_score[i][1] += pk::rand(6);
                if (i == 工事_太鼓台) facility_score[i][1] += pk::rand(3);

                if (pk::has_tech(src_base, 技巧_开发投石) and i == 工事_投石台) facility_score[i][1] += 3;
                if (pk::has_tech(src_base, 技巧_设施强化) and i == 工事_阵) facility_score[i][1] += 1;
                if (pk::has_tech(src_base, 技巧_设施强化) and i == 工事_箭塔) facility_score[i][1] += 1;
            }

            facility_score.sort(function(a, b) {
                return a[1] > b[1];
            });

           // pk::trace(pk::decode(pk::get_name(src_base)) + "6目标" +  123);
            int facility_type = facility_score[0][0];
            if (facility_type < 0 or facility_type >= 9) return -1;

            if (do_cmd)
            {
                // 创建出征指令信息
                pk::com_march_cmd_info cmd;
                @cmd.base = @src_base;
                cmd.type = 部队类型_战斗;
                cmd.member[0] = person.get_id();
                cmd.gold = 800;
                cmd.troops = pk::max(3000, unit_troops);
                cmd.weapon_id[0] = ground_weapon_id;
                cmd.weapon_id[1] = water_weapon_id;
                cmd.weapon_amount[0] = (is_siege_weapon(ground_weapon_id)) ? 1 : pk::max(1, unit_troops);
                cmd.weapon_amount[1] = 0;
                cmd.food = pk::min(50000, unit_food);

                cmd.order = 部队任务_设置;
                cmd.target_pos = target_pos1; // 设置目标
                cmd.target = facility_type; // 设置目标



                if (cmd.weapon_id[0] == -1)
                    return -1;

                int unit_id = pk::command(cmd);


                // 执行出征指令

                if (unit_id == -1)
                    return -1;


                pk::unit @unit_cmd = pk::get_unit(unit_id);
                if (pk::is_alive(unit_cmd))
                {
                    pk::get_scenario().ai_table.unit[unit_id].deploy_type = 部队出征类型_建设;
                    pk::get_scenario().ai_table.unit[unit_id].deploy_target = src_base.get_id();

                    unit_cmd.action_done = true; // 设置部队行动完成

                    string src_name = pk::decode(pk::get_name(src_base));
                    string unit_name = pk::decode(pk::get_name(pk::get_person(unit_cmd.leader)));
                    string weapon_name = get_weapon_name(unit_cmd.weapon);
                   // pk::info(pk::format("建设部队: {},目标为{},{}", pk::decode(pk::get_name(unit_cmd)),target_pos1.x, target_pos1.y));

                    return unit_id;
                }
            }

            return -1;
        }



        //******************************************* 攻城工具判断   ****************************************************************
        bool is_siege_weapon(int weapon_id)
        {
            if (兵器_冲车 <= weapon_id and weapon_id <= 兵器_木兽)
                return true;
            return false;
        }

        //******************************************* 武器选择函数   ****************************************************************
        pk::int_int get_ground_weapon(pk::building @base, pk::person @leader, int type)
        {
            array<int> heishu_score(兵器_末, 0);    // 适性评分，是否可以参考副将补全
            array<bool> can_march(兵器_末, false);  // 是否有足够兵器可出征
            array<int> tech_score(兵器_末, 0);      // 已研究科技评分
            array<int> ling_score(兵器_末, 0);      // 根据态势调整
            array<int> skill_score(兵器_末, 0); // 总特技评分
            array<int> all_score(兵器_末, 0);       // 兵器和适性的总评分

            pk::force @force0 = pk::get_force(leader.get_force_id());
            for (int i = 0; i < 兵器_走舸; i++)
            {

                if ((i == 兵器_冲车 or i == 兵器_木兽 or i == 兵器_井阑 or i == 兵器_投石))// 冲车木兽不在建设时出动
                    can_march[i] = false;

                else if (check_weapon_able(base, i))
                    can_march[i] = true;

                if (can_march[i])
                {
                    if (i == 兵器_戟)  ling_score[i] += 6;
                    if (i == 兵器_战马)  ling_score[i] += 3;

                    if (i == 兵器_剑)  heishu_score[i] = 0;
                    else heishu_score[i] = leader.tekisei[pk::equipment_id_to_heishu(i)];
                    tech_score[i] = ch::get_tech_score(force0, i);

                    int skill_id = leader.skill;
                    if (skill_id < 211 and skill_id >-1)
                    {
                    //pk::trace(pk::decode(pk::get_name(leader)) + get_weapon_name(i) + "i:" +i + "skill_id :" +skill_id );
                        skill_score[i] = ai出征优化::skill_score[skill_id][i];
                    }
                    all_score[i] = heishu_score[i] * 3 + tech_score[i] + skill_score[i] + ling_score[i];

                    //pk::trace(pk::decode(pk::get_name(leader)) + get_weapon_name(i) + "科技分:" + tech_score[i] + "特技分:" + skill_score[i] + ",适性分:" + heishu_score[i] * 3 + ",态势分:" + ling_score[i] + ",总分:" + all_score[i]);

                }
            }

            return pk::int_int(get_arr_max(all_score));
        }

        pk::int_int get_arr_max(array<int> score)
        {
            int best_score = 0;
            int id = 0;
            for (int i = 0; i < int(score.length); i++)
            {
                if (score[i] > best_score)
                {
                    best_score = score[i];
                    id = i;
                }
            }

            return pk::int_int(id, best_score);
        }

        //---------------------------------------------------------------------------------------

        bool check_weapon_able(pk::building @building, int weapon_id)
        {
            bool 投石科技 = pk::has_tech(building, 技巧_投石开发);
            bool 木兽科技 = pk::has_tech(building, 技巧_木兽开发);

            //pk::trace(pk::decode(pk::get_name(src_base)) + "兵器id" + weapon_id + "数量" + pk::get_weapon_amount(building, weapon_id));
            if (weapon_id == 兵器_剑 or weapon_id == 兵器_走舸)
                return true;
            if (weapon_id == 兵器_投石 and !投石科技)
                return false;

            if (weapon_id == 兵器_木兽 and !木兽科技)
                return false;

            if (weapon_id > 兵器_战马)
            {
                if (pk::get_weapon_amount(building, weapon_id) >= 1)
                    return true;
            }
            else
            {
                if (pk::get_weapon_amount(building, weapon_id) >= 6000)
                    return true;
            }
            return false;
        }

        pk::point get_empty_pos(pk::point pos, int distance_min, int distance_max)
        {
            array<pk::point> range_pos_arr = pk::range(pos, distance_min, distance_max);
            for (int arr_index = 0; arr_index < int(range_pos_arr.length); arr_index++)
            {
                pk::point range_pos = range_pos_arr[arr_index];
                if (!pk::is_valid_pos(range_pos))
                    continue;

                pk::hex @hex = pk::get_hex(range_pos);
                if (hex.has_building)
                    continue;
                if (hex.has_unit)
                    continue;

                int terrain_id = hex.terrain;
                if (!pk::is_valid_terrain_id(terrain_id))
                    continue;
                if (!pk::is_enabled_terrain(terrain_id))
                    continue;

                return range_pos;
            }

            return pk::point(-1, -1);
        }


        pk::point get_able_pos(pk::building @building, int distance_min, int distance_max)
        {
            array<pk::point> range_pos_arr = pk::range(building.pos, distance_min, distance_max);
            for (int arr_index = 0; arr_index < int(range_pos_arr.length); arr_index++)
            {
                pk::point range_pos = range_pos_arr[arr_index];
                if (!pk::is_valid_pos(range_pos))
                    continue;

                if (pk::get_building_id(range_pos) != building.get_id())
                    continue;

                pk::hex @hex = pk::get_hex(range_pos);
                if (hex.has_building)
                    continue;
                if (hex.has_unit)
                    continue;

                if (!hex.can_military)
                    continue;
                if (pk::is_water_terrain(hex.terrain))
                    continue;

                if (hex.terrain != 地形_官道 and hex.terrain != 地形_土 and hex.terrain != 地形_草地 and hex.terrain != 地形_砂地)
                    continue;

                bool development_around = false;
                pk::array<pk::point> range = pk::range(range_pos, 1, 3);
                for (int j = 0; j < int(range.length); j++)
                {
                    if (pk::is_valid_pos(range[j]))
                    {
                        pk::hex@ hex0 = pk::get_hex(range[j]);

                        if (hex0.development or pk::get_model_id(range[j]) == 45 or hex0.has_building)
                        {
                            development_around = true;
                        }

                    }
                }
                if (development_around)
                    continue;

                int terrain_id = hex.terrain;
                if (!pk::is_valid_terrain_id(terrain_id))
                    continue;
                if (!pk::is_enabled_terrain(terrain_id))
                    continue;

                return range_pos;
            }

            return pk::point(-1, -1);
        }

    //=======================================================================================

        string get_weapon_name(int weapon_id)
        {
            string weapon_name;
            switch (weapon_id)
            {
                case 兵器_剑:
                    weapon_name = "剑兵";
                    break;
                case 兵器_枪:
                    weapon_name = "枪兵";
                    break;
                case 兵器_戟:
                    weapon_name = "戟兵";
                    break;
                case 兵器_弩:
                    weapon_name = "弩兵";
                    break;
                case 兵器_战马:
                    weapon_name = "骑兵";
                    break;
                case 兵器_冲车:
                    weapon_name = "冲车";
                    break;
                case 兵器_井阑:
                    weapon_name = "井阑";
                    break;
                case 兵器_投石:
                    weapon_name = "投石";
                    break;
                case 兵器_木兽:
                    weapon_name = "木兽";
                    break;
                case 兵器_走舸:
                    weapon_name = "水军";
                    break;
                case 兵器_楼船:
                    weapon_name = "水军";
                    break;
                case 兵器_斗舰:
                    weapon_name = "水军";
                    break;
                default:
                    weapon_name = "??";
                    break;
            }
            return weapon_name;
        }

        string get_order_info(int order)
        {
            string name;
            switch (order)
            {
                case 0:
                    name = "部队任务_待命";
                    break;
                case 1:
                    name = "部队任务_移动";
                    break;
                case 2:
                    name = "部队任务_设置";
                    break;
                case 3:
                    name = "部队任务_攻击";
                    break;
                case 4:
                    name = "部队任务_撤退";
                    break;
                case 5:
                    name = "部队任务_拦截";
                    break;
                case 6:
                    name = "部队任务_护卫";
                    break;
                case 7:
                    name = "部队任务_攻城";
                    break;
                case 8:
                    name = "部队任务_修复";
                    break;
                case 9:
                    name = "部队任务_征服";
                    break;
                case 10:
                    name = "部队任务_补给";
                    break;
                case 11:
                    name = "部队任务_歼灭";
                    break;
                case 12:
                    name = "部队任务_追随";
                    break;
                case 13:
                    name = "部队任务_末";
                    break;
                default:
                    name = "部队任务_没有";
                    break;
            }

            return name;
        }

        //---------------------------------------------------------------------------------------
    };

    Main main;
}